"""
配置管理器主类
统一管理配置的加载、更新、缓存、通知等功能
"""

import asyncio
import json
import logging
import os
from datetime import datetime
from typing import Dict, List, Optional, Any, Union

from .database import DatabaseManager, ConfigRepository
from .history import ConfigHistoryManager
from .backup import ConfigBackupManager
from .validator import ConfigValidator
from .notifier import ConfigNotifier, CompositeNotifier
from .reloader import ConfigReloader, ServiceRestarter, GracefulShutdownHandler, ConfigManagerExtensions
from data_models.Config import (
    ConfigItem, ConfigGroup, ConfigChange, ValidationResult,
    DataType, ConfigChangeType
)


class ConfigManager:
    """
    配置管理器 - 单例模式

    提供配置的统一管理，包括：
    - 配置加载和缓存
    - 配置更新和验证
    - 配置历史记录
    - 配置备份和恢复
    - 配置变更通知
    """

    _instance = None
    _initialized = False

    def __new__(cls, db_config: Dict[str, Any] = None):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, db_config: Dict[str, Any] = None):
        if not ConfigManager._initialized:
            self._config_cache: Dict[str, Any] = {}
            self._config_metadata: Dict[str, Dict] = {}
            self._config_groups: Dict[int, ConfigGroup] = {}
            self._subscribers: List[ConfigNotifier] = []
            self._lock = asyncio.Lock()
            self.logger = logging.getLogger(__name__)
            self._db_config = db_config

            # 初始化组件
            if db_config:
                self._db_manager = DatabaseManager(db_config)
                self._repository = ConfigRepository(self._db_manager)
                self._history_manager = ConfigHistoryManager(self._db_manager)
                self._backup_manager = ConfigBackupManager(self._db_manager)
                self._validator = ConfigValidator(self._db_manager)

                # 创建默认通知器
                self._notifier = CompositeNotifier([
                    # 可以添加更多默认通知器
                ])

                # 使用扩展功能初始化热重载和服务重启
                ConfigManagerExtensions.setup_reload_and_restart(self)

            ConfigManager._initialized = True

    async def initialize(self) -> bool:
        """
        初始化配置管理器

        Returns:
            bool: 初始化是否成功
        """
        try:
            if not self._db_config:
                raise ValueError("Database configuration not provided")

            # 初始化数据库连接
            await self._db_manager.initialize()

            # 测试数据库连接
            if not await self._db_manager.test_connection():
                raise Exception("Database connection test failed")

            # 加载配置数据
            await self.load_all_configs()

            self.logger.info("ConfigManager initialized successfully")
            return True

        except Exception as e:
            self.logger.error(f"Failed to initialize ConfigManager: {e}")
            return False

    async def close(self):
        """关闭配置管理器"""
        try:
            if hasattr(self, '_db_manager'):
                await self._db_manager.close()
            self.logger.info("ConfigManager closed")
        except Exception as e:
            self.logger.error(f"Error closing ConfigManager: {e}")

    # ==================== 配置加载相关方法 ====================

    async def load_all_configs(self) -> bool:
        """
        从数据库加载所有配置项到缓存

        Returns:
            bool: 加载是否成功
        """
        async with self._lock:
            try:
                # 清空现有缓存
                self._config_cache.clear()
                self._config_metadata.clear()
                self._config_groups.clear()

                # 加载配置分组
                groups = await self._repository.get_config_groups()
                for group_data in groups:
                    group = ConfigGroup(**group_data)
                    self._config_groups[group.id] = group

                # 加载配置项
                items, _ = await self._repository.get_config_items()
                for item_data in items:
                    item = ConfigItem(**item_data)
                    key = item.key_name

                    # 解析并缓存配置值
                    current_value = item.current_value or item.default_value
                    if current_value is not None:
                        parsed_value = self._parse_config_value(current_value, item.data_type)
                        self._config_cache[key] = parsed_value

                    # 缓存配置元数据
                    self._config_metadata[key] = {
                        'id': item.id,
                        'data_type': item.data_type,
                        'is_reload_required': item.is_reload_required,
                        'is_sensitive': item.is_sensitive,
                        'group_id': item.group_id,
                        'category': item.category,
                        'group_name': self._config_groups.get(item.group_id).__dict__.get('name', '') if item.group_id in self._config_groups else '',
                        'display_name': item.display_name,
                        'description': item.description,
                        'validation_rule': item.validation_rule,
                        'value_range': item.value_range
                    }

                self.logger.info(f"Loaded {len(items)} configuration items from {len(groups)} groups")
                return True

            except Exception as e:
                self.logger.error(f"Failed to load configurations: {e}")
                return False

    async def reload_config(self, key: str = None, changed_by: str = "system") -> bool:
        """
        热重载配置

        Args:
            key: 配置键名，None表示重载所有配置
            changed_by: 操作人

        Returns:
            bool: 重载是否成功
        """
        try:
            if key:
                # 重载单个配置
                await self._reload_single_config(key)

                # 记录重载操作
                metadata = self._config_metadata.get(key)
                if metadata:
                    await self._history_manager.record_config_reload(key, changed_by)

                # 通知配置重载
                await self._notify_config_reloaded(key)

                self.logger.info(f"Configuration reloaded: {key}")
            else:
                # 重载所有配置
                await self.load_all_configs()
                await self._history_manager.record_config_reload(None, changed_by)
                await self._notify_config_reloaded()

                self.logger.info("All configurations reloaded")

            return True

        except Exception as e:
            self.logger.error(f"Failed to reload configuration: {e}")
            return False

    async def _reload_single_config(self, key: str):
        """重载单个配置项"""
        item = await self._repository.get_config_item_by_key(key)
        if item:
            value = item.current_value or item.default_value
            if value is not None:
                parsed_value = self._parse_config_value(value, item.data_type)
                self._config_cache[key] = parsed_value

    # ==================== 配置获取相关方法 ====================

    async def get_config(self, key: str, default: Any = None) -> Any:
        """
        获取配置值

        Args:
            key: 配置键名
            default: 默认值

        Returns:
            Any: 配置值
        """
        async with self._lock:
            if key in self._config_cache:
                return self._config_cache[key]

            # 回退到环境变量或默认值
            return os.getenv(key, default)

    async def get_config_with_metadata(self, key: str) -> Dict[str, Any]:
        """
        获取配置值及其元数据

        Args:
            key: 配置键名

        Returns:
            Dict[str, Any]: 包含值和元数据的字典
        """
        async with self._lock:
            value = await self.get_config(key)
            metadata = self._config_metadata.get(key, {})

            return {
                'key': key,
                'value': value,
                'metadata': metadata
            }

    async def get_all_configs(self) -> Dict[str, Any]:
        """
        获取所有配置

        Returns:
            Dict[str, Any]: 所有配置的字典
        """
        async with self._lock:
            return self._config_cache.copy()

    async def get_configs_by_group(self, group_name: str) -> Dict[str, Any]:
        """
        获取指定分组的配置

        Args:
            group_name: 分组名称

        Returns:
            Dict[str, Any]: 分组配置字典
        """
        async with self._lock:
            group_configs = {}
            for key, metadata in self._config_metadata.items():
                if metadata.get('group_name') == group_name:
                    group_configs[key] = self._config_cache.get(key)
            return group_configs

    # ==================== 配置更新相关方法 ====================

    async def update_config(self, key: str, value: Any, changed_by: str = "system",
                           change_reason: str = None, ip_address: str = None,
                           user_agent: str = None) -> bool:
        """
        更新配置值

        Args:
            key: 配置键名
            value: 新值
            changed_by: 操作人
            change_reason: 变更原因
            ip_address: 操作IP地址
            user_agent: 用户代理

        Returns:
            bool: 更新是否成功
        """
        async with self._lock:
            try:
                # 1. 验证配置
                metadata = self._config_metadata.get(key)
                if not metadata:
                    self.logger.error(f"Unknown configuration key: {key}")
                    return False

                validation_result = await self._validator.validate_config_value(
                    key, str(value), metadata
                )
                if not validation_result.is_valid:
                    self.logger.error(f"Invalid config value for {key}: {validation_result.error_message}")
                    return False

                # 2. 获取旧值
                old_value = self._config_cache.get(key)

                # 3. 检查配置是否为只读
                item = await self._repository.get_config_item_by_key(key)
                if item and item.is_readonly:
                    self.logger.error(f"Configuration {key} is readonly")
                    return False

                # 4. 更新数据库
                success = await self._repository.update_config_value(
                    key, validation_result.normalized_value
                )
                if not success:
                    self.logger.error(f"Failed to update config {key} in database")
                    return False

                # 5. 更新缓存
                parsed_value = self._parse_config_value(validation_result.normalized_value, metadata['data_type'])
                self._config_cache[key] = parsed_value

                # 6. 记录历史
                await self._history_manager.record_config_update(
                    config_key=key,
                    config_id=metadata['id'],
                    old_value=str(old_value) if old_value is not None else None,
                    new_value=validation_result.normalized_value,
                    changed_by=changed_by,
                    change_reason=change_reason,
                    ip_address=ip_address,
                    user_agent=user_agent
                )

                # 7. 通知订阅者
                await self._notify_config_changed(key, old_value, parsed_value)

                self.logger.info(f"Configuration '{key}' updated by {changed_by}")
                return True

            except Exception as e:
                self.logger.error(f"Failed to update configuration '{key}': {e}")
                return False

    async def batch_update_configs(self, updates: Dict[str, Any],
                                  changed_by: str = "system", change_reason: str = None) -> Dict[str, bool]:
        """
        批量更新配置

        Args:
            updates: 配置更新字典 {key: value}
            changed_by: 操作人
            change_reason: 变更原因

        Returns:
            Dict[str, bool]: 更新结果字典
        """
        results = {}

        async with self._lock:
            for key, value in updates.items():
                results[key] = await self.update_config(key, value, changed_by, change_reason)

        return results

    async def validate_config_value(self, key: str, value: str) -> ValidationResult:
        """
        验证配置值（不更新）

        Args:
            key: 配置键名
            value: 配置值

        Returns:
            ValidationResult: 验证结果
        """
        metadata = self._config_metadata.get(key)
        return await self._validator.validate_config_value(key, value, metadata)

    # ==================== 配置分组管理 ====================

    async def get_config_groups(self) -> List[ConfigGroup]:
        """获取所有配置分组"""
        async with self._lock:
            return list(self._config_groups.values())

    async def get_config_items(self, group_id: int = None, category: str = None,
                               search: str = None) -> List[ConfigItem]:
        """
        获取配置项列表

        Args:
            group_id: 分组ID
            category: 分类
            search: 搜索关键词

        Returns:
            List[ConfigItem]: 配置项列表
        """
        items, _ = await self._repository.get_config_items(group_id, category, search)
        return [ConfigItem(**item) for item in items]

    # ==================== 配置历史管理 ====================

    async def get_config_history(self, config_key: str, limit: int = 50) -> List[Dict]:
        """获取配置变更历史"""
        return await self._history_manager.get_config_history(config_key, limit)

    async def get_recent_changes(self, hours: int = 24) -> List[Dict]:
        """获取最近的配置变更"""
        return await self._history_manager.get_recent_changes(hours)

    # ==================== 配置备份管理 ====================

    async def create_backup(self, backup_name: str, created_by: str = "system",
                           description: str = None) -> str:
        """
        创建配置备份

        Args:
            backup_name: 备份名称
            created_by: 创建人
            description: 备份描述

        Returns:
            str: 备份ID
        """
        configs = await self.get_all_configs()
        backup_id = await self._backup_manager.create_backup(
            backup_name=backup_name,
            configs=configs,
            created_by=created_by,
            description=description
        )
        return str(backup_id)

    async def restore_backup(self, backup_id: str, created_by: str = "system") -> bool:
        """
        恢复配置备份

        Args:
            backup_id: 备份ID
            created_by: 操作人

        Returns:
            bool: 恢复是否成功
        """
        try:
            # 获取恢复计划
            current_configs = await self.get_all_configs()
            restore_plan = await self._backup_manager.get_restore_plan(
                int(backup_id), current_configs
            )

            if 'error' in restore_plan:
                self.logger.error(f"Restore plan error: {restore_plan['error']}")
                return False

            # 执行恢复
            backup_data = json.loads((await self._backup_manager.get_backup(int(backup_id)))['backup_data'])
            backup_configs = backup_data.get('configs', {})

            results = await self.batch_update_configs(
                {key: config_info['value'] for key, config_info in backup_configs.items()
                 if config_info.get('value') is not None},
                changed_by=created_by,
                change_reason=f"Restore from backup {backup_id}"
            )

            success_count = sum(1 for success in results.values() if success)
            total_count = len(results)

            self.logger.info(f"Backup restore completed: {success_count}/{total_count} items restored")
            return success_count == total_count

        except Exception as e:
            self.logger.error(f"Failed to restore configuration backup: {e}")
            return False

    async def list_backups(self, limit: int = 50) -> List[Dict]:
        """列出配置备份"""
        return await self._backup_manager.list_backups(limit)

    # ==================== 配置通知管理 ====================

    def subscribe_to_changes(self, notifier: ConfigNotifier):
        """订阅配置变更通知"""
        if notifier not in self._subscribers:
            self._subscribers.append(notifier)
            self.logger.info(f"Added subscriber: {type(notifier).__name__}")

    def unsubscribe_from_changes(self, notifier: ConfigNotifier):
        """取消订阅配置变更通知"""
        if notifier in self._subscribers:
            self._subscribers.remove(notifier)
            self.logger.info(f"Removed subscriber: {type(notifier).__name__}")

    async def _notify_config_changed(self, key: str, old_value: Any, new_value: Any):
        """通知配置变更"""
        for subscriber in self._subscribers:
            try:
                await subscriber.on_config_changed(key, old_value, new_value)
            except Exception as e:
                self.logger.error(f"Error notifying subscriber {type(subscriber).__name__}: {e}")

    async def _notify_config_reloaded(self, key: str = None):
        """通知配置重载"""
        for subscriber in self._subscribers:
            try:
                await subscriber.on_config_reloaded(key)
            except Exception as e:
                self.logger.error(f"Error notifying subscriber {type(subscriber).__name__}: {e}")

    async def _notify_service_restart(self):
        """通知服务重启"""
        for subscriber in self._subscribers:
            try:
                await subscriber.on_service_restart()
            except Exception as e:
                self.logger.error(f"Error notifying subscriber {type(subscriber).__name__}: {e}")

    # ==================== 系统状态和统计 ====================

    async def get_config_status(self) -> Dict[str, Any]:
        """获取配置系统状态"""
        try:
            # 获取统计信息
            stats = await self._repository.get_config_statistics()

            status = {
                'system_status': 'healthy',
                'total_configs': stats.get('total', 0),
                'sensitive_configs': stats.get('sensitive_count', 0),
                'reload_required_configs': stats.get('reload_required_count', 0),
                'config_groups': stats.get('config_groups', 0),
                'last_update': stats.get('last_update'),
                'cache_size': len(self._config_cache),
                'subscriber_count': len(self._subscribers),
                'database_connected': await self._db_manager.test_connection() if hasattr(self, '_db_manager') else False
            }

            # 转换时间为ISO格式
            if status['last_update']:
                status['last_update'] = status['last_update'].isoformat()

            return status

        except Exception as e:
            self.logger.error(f"Failed to get config status: {e}")
            return {
                'system_status': 'error',
                'error': str(e)
            }

    # ==================== 工具方法 ====================

    def _parse_config_value(self, value: str, data_type: str) -> Any:
        """根据数据类型解析配置值"""
        if value is None:
            return None

        try:
            if data_type == DataType.BOOLEAN.value:
                return value.lower() in ('true', '1', 'yes', 'on')
            elif data_type == DataType.INTEGER.value:
                return int(value)
            elif data_type == DataType.FLOAT.value:
                return float(value)
            elif data_type == DataType.JSON.value:
                return json.loads(value)
            else:
                return value
        except (ValueError, json.JSONDecodeError):
            return value

    async def export_configs(self, format: str = 'json') -> str:
        """
        导出所有配置

        Args:
            format: 导出格式

        Returns:
            str: 导出的配置数据
        """
        try:
            configs = await self.get_all_configs()

            if format.lower() == 'json':
                export_data = {
                    'timestamp': datetime.now().isoformat(),
                    'version': '1.0',
                    'configs': {}
                }

                for key, value in configs.items():
                    metadata = self._config_metadata.get(key, {})
                    export_data['configs'][key] = {
                        'value': str(value) if value is not None else None,
                        'data_type': metadata.get('data_type'),
                        'category': metadata.get('category'),
                        'group_name': metadata.get('group_name')
                    }

                return json.dumps(export_data, indent=2, ensure_ascii=False)
            else:
                raise ValueError(f"Unsupported export format: {format}")

        except Exception as e:
            self.logger.error(f"Failed to export configs: {e}")
            return ""